using Avalonia.Media.Imaging;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Threading.Tasks;
using Material.Icons;
using System.IO;
using System;
using Avalonia.Platform.Storage;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using MathPlus.Features.ScreenShot;
using PaddleOCRSharp;
using System.Drawing;
using System.Runtime.Versioning;

namespace MathPlus.Features.TextOCR;

public partial class TextOCRViewModel : DemoPageBase, IDisposable
{
    private readonly OCRModelConfig _modelConfig;
    private readonly PaddleOCREngine? _engine;

    private IStorageProvider? StorageProvider
    {
        get
        {
            if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
            {
                return desktop.MainWindow?.StorageProvider;
            }
            return null;
        }
    }

    public TextOCRViewModel() : base("Text OCR", MaterialIconKind.Pencil, -150)
    {
        try
        {
            var modelPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "inference");
     
            if (!Directory.Exists(modelPath))
            {
                Directory.CreateDirectory(modelPath);
                RecognizedText = "Please copy PaddleOCR model files to the 'inference' directory";
                return;
            }

            _modelConfig = new OCRModelConfig()
            {
                det_infer = Path.Combine(modelPath, "ch_PP-OCRv4_det_infer"),
                cls_infer = Path.Combine(modelPath, "ch_ppocr_mobile_v2.0_cls_infer"),
                rec_infer = Path.Combine(modelPath, "ch_PP-OCRv4_rec_infer"),
                keys = Path.Combine(modelPath, "ppocr_keys.txt")
            };

            if (!File.Exists(Path.Combine(_modelConfig.det_infer, "inference.pdmodel")))
            {
                RecognizedText = $"PaddleOCR model files not found. {modelPath} Please copy them to the 'inference' directory";
                return;
            }

            _engine = new PaddleOCREngine(_modelConfig);
        }
        catch (Exception ex)
        {
            RecognizedText = $"Error initializing OCR engine: {ex.Message}";
        }
    }

    [ObservableProperty]
    private Avalonia.Media.Imaging.Bitmap? selectedImage;

    [ObservableProperty]
    private string? recognizedText;

    private Avalonia.Media.Imaging.Bitmap? _previousImage;

    partial void OnSelectedImageChanged(Avalonia.Media.Imaging.Bitmap? value)
    {
        if (value != null)
        {
            RecognizeText(value);
        }
        
        // Dispose previous image if exists
        _previousImage?.Dispose();
        _previousImage = value;
    }

    [SupportedOSPlatform("windows")]
    private void RecognizeText(Avalonia.Media.Imaging.Bitmap avaloniaImage)
    {
        if (_engine == null)
        {
            RecognizedText = "OCR engine not initialized. Please check model files.";
            return;
        }

        try
        {
            // Convert Avalonia.Media.Imaging.Bitmap to System.Drawing.Bitmap
            using var memoryStream = new MemoryStream();
            avaloniaImage.Save(memoryStream);
            memoryStream.Position = 0;
            
            using var drawingBitmap = new System.Drawing.Bitmap(memoryStream);
            var result = _engine.DetectText(drawingBitmap);
            
            if (result != null && result.Text != null)
            {
                RecognizedText = result.Text;
            }
            else
            {
                RecognizedText = "No text detected";
            }
        }
        catch (Exception ex)
        {
            RecognizedText = $"Error recognizing text: {ex.Message}";
        }
    }

    [RelayCommand]
    private async Task SelectImage()
    {
        var storageProvider = StorageProvider;
        if (storageProvider == null)
        {
            RecognizedText = "Error: Storage provider not available";
            return;
        }

        var fileTypes = new FilePickerFileType[]
        {
            new("Image Files")
            {
                Patterns = new[] { "*.png", "*.jpg", "*.jpeg", "*.bmp" },
                MimeTypes = new[] { "image/png", "image/jpeg", "image/bmp" }
            }
        };

        var options = new FilePickerOpenOptions
        {
            Title = "Select Image",
            AllowMultiple = false,
            FileTypeFilter = fileTypes
        };

        var result = await storageProvider.OpenFilePickerAsync(options);
        var file = result.FirstOrDefault();

        if (file != null)
        {
            try
            {
                var stream = await file.OpenReadAsync();
                SelectedImage = new Avalonia.Media.Imaging.Bitmap(stream);
            }
            catch (Exception ex)
            {
                RecognizedText = $"Error loading image: {ex.Message}";
            }
        }
    }

    [RelayCommand]
    private async Task CaptureScreen()
    {
        if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop &&
            desktop.MainWindow != null)
        {
            var mainWindow = desktop.MainWindow;
            
            var screenshotWindow = new ScreenShotView();
            var tcs = new TaskCompletionSource();

            screenshotWindow.Closed += (s, e) =>
            {
                mainWindow.Show();
                tcs.SetResult();
            };

            mainWindow.Hide();
            screenshotWindow.Show();

            await tcs.Task;
        }
    }

    [RelayCommand]
    private async Task SaveResult()
    {
        if (string.IsNullOrEmpty(RecognizedText))
        {
            RecognizedText = "No text to save";
            return;
        }

        var storageProvider = StorageProvider;
        if (storageProvider == null)
        {
            RecognizedText = "Error: Storage provider not available";
            return;
        }

        var options = new FilePickerSaveOptions
        {
            Title = "Save OCR Result",
            DefaultExtension = ".txt",
            SuggestedFileName = $"OCR_Result_{DateTime.Now:yyyyMMdd_HHmmss}.txt"
        };

        var file = await storageProvider.SaveFilePickerAsync(options);
        if (file != null)
        {
            try
            {
                await using var stream = await file.OpenWriteAsync();
                using var writer = new StreamWriter(stream);
                await writer.WriteAsync(RecognizedText);
            }
            catch (Exception ex)
            {
                RecognizedText = $"Error saving result: {ex.Message}";
            }
        }
    }

    [RelayCommand]
    private async Task ExportDoc()
    {
        if (string.IsNullOrEmpty(RecognizedText))
        {
            RecognizedText = "No text to export";
            return;
        }

        var storageProvider = StorageProvider;
        if (storageProvider == null)
        {
            RecognizedText = "Error: Storage provider not available";
            return;
        }

        var options = new FilePickerSaveOptions
        {
            Title = "Export as Document",
            DefaultExtension = ".docx",
            SuggestedFileName = $"OCR_Doc_{DateTime.Now:yyyyMMdd_HHmmss}.docx"
        };

        var file = await storageProvider.SaveFilePickerAsync(options);
        if (file != null)
        {
            try
            {
                // For now, we'll save as text since we haven't implemented DOCX export
                await using var stream = await file.OpenWriteAsync();
                using var writer = new StreamWriter(stream);
                await writer.WriteAsync(RecognizedText);
            }
            catch (Exception ex)
            {
                RecognizedText = $"Error exporting document: {ex.Message}";
            }
        }
    }

    public void Dispose()
    {
        _engine?.Dispose();
        _previousImage?.Dispose();
    }

    public async Task HandleDroppedFileAsync(string filePath)
    {
        try
        {
            if (!IsImageFile(filePath))
            {
                // TODO: Show error message
                return;
            }

            using var stream = File.OpenRead(filePath);
            var bitmap = new Avalonia.Media.Imaging.Bitmap(stream);
            SelectedImage = bitmap;
            
            // TODO: Implement OCR processing
            RecognizeText(bitmap);
        }
        catch (Exception ex)
        {
            // TODO: Show error message
            RecognizedText = $"Error loading image: {ex.Message}";
        }
    }

    private bool IsImageFile(string filePath)
    {
        var extension = Path.GetExtension(filePath).ToLower();
        return extension is ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif";
    }
}
